

library ieee;

use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.sha_pack.all;
entity sha_top is
  port(
    clk    : in std_logic;
    rst    : in std_logic;
    word   : in std_logic_vector(31 downto 0);
    finish : in std_logic;
    init   : in std_logic;
    setup  : in std_logic; -- To configure the mode
    mode   : in std_logic_vector(1 downto 0); -- "00": sha2-256, "11": sha2-512
    busy   : out std_logic;
    output_V : out std_logic_vector(255 downto 0)
  );
end entity;

architecture rtl of sha_top is
    type H_C is array(0 to 7) of std_logic_vector(31 downto 0);
    constant HC :H_C := (x"6a09e667", X"bb67ae85", X"3c6ef372", X"a54ff53a", x"510e527f", X"9b05688c", X"1f83d9ab", X"5be0cd19");
   -- type H_C is array(0 to 7) of std_logic_vector(63 downto 0);
   -- constant HC :H_C := (x"6a09e667f3bcc908", X"bb67ae8584caa73b", X"3c6ef372fe94f82b", X"a54ff53a5f1d36f1",
                        -- x"510e527fade682d1", X"9b05688c2b3e6c1f", X"1f83d9abfb41bd6b", X"5be0cd19137e2179");
   
   signal Hnew : H_C ;
   
   
  -- type K_C is array(0 to 63) of std_logic_vector(31 downto 0);
  -- constant K :K_C := (X"428a2f98", X"71374491", X"b5c0fbcf", X"e9b5dba5", X"3956c25b", X"59f111f1", X"923f82a4", X"ab1c5ed5",
                       -- X"d807aa98", X"12835b01", X"243185be", X"550c7dc3", X"72be5d74", X"80deb1fe", X"9bdc06a7", X"c19bf174",
                       -- X"e49b69c1", X"efbe4786", X"0fc19dc6", X"240ca1cc", X"2de92c6f", X"4a7484aa", X"5cb0a9dc", X"76f988da",
                       -- X"983e5152", X"a831c66d", X"b00327c8", X"bf597fc7", X"c6e00bf3", X"d5a79147", X"06ca6351", X"14292967",
                       -- X"27b70a85", X"2e1b2138", X"4d2c6dfc", X"53380d13", X"650a7354", X"766a0abb", X"81c2c92e", X"92722c85",
                       -- X"a2bfe8a1", X"a81a664b", X"c24b8b70", X"c76c51a3", X"d192e819", X"d6990624", X"f40e3585", X"106aa070",
                       -- X"19a4c116", X"1e376c08", X"2748774c", X"34b0bcb5", X"391c0cb3", X"4ed8aa4a", X"5b9cca4f", X"682e6ff3",
                       -- X"748f82ee", X"78a5636f", X"84c87814", X"8cc70208", X"90befffa", X"a4506ceb", X"bef9a3f7", X"c67178f2");
  type K_C is array(0 to 79) of std_logic_vector(63 downto 0);
  constant K :K_C:= ( X"428a2f98d728ae22", X"7137449123ef65cd", X"b5c0fbcfec4d3b2f", X"e9b5dba58189dbbc", 
                      X"3956c25bf348b538", X"59f111f1b605d019", X"923f82a4af194f9b", X"ab1c5ed5da6d8118", 
                      X"d807aa98a3030242", X"12835b0145706fbe", X"243185be4ee4b28c", X"550c7dc3d5ffb4e2", 
                      X"72be5d74f27b896f", X"80deb1fe3b1696b1", X"9bdc06a725c71235", X"c19bf174cf692694", 
                      X"e49b69c19ef14ad2", X"efbe4786384f25e3", X"0fc19dc68b8cd5b5", X"240ca1cc77ac9c65", 
                      X"2de92c6f592b0275", X"4a7484aa6ea6e483", X"5cb0a9dcbd41fbd4", X"76f988da831153b5", 
                      X"983e5152ee66dfab", X"a831c66d2db43210", X"b00327c898fb213f", X"bf597fc7beef0ee4", 
                      X"c6e00bf33da88fc2", X"d5a79147930aa725", X"06ca6351e003826f", X"142929670a0e6e70", 
                      X"27b70a8546d22ffc", X"2e1b21385c26c926", X"4d2c6dfc5ac42aed", X"53380d139d95b3df", 
                      X"650a73548baf63de", X"766a0abb3c77b2a8", X"81c2c92e47edaee6", X"92722c851482353b", 
                      X"a2bfe8a14cf10364", X"a81a664bbc423001", X"c24b8b70d0f89791", X"c76c51a30654be30", 
                      X"d192e819d6ef5218", X"d69906245565a910", X"f40e35855771202a", X"106aa07032bbd1b8", 
                      X"19a4c116b8d2d0c8", X"1e376c085141ab53", X"2748774cdf8eeb99", X"34b0bcb5e19b48a8", 
                      X"391c0cb3c5c95a63", X"4ed8aa4ae3418acb", X"5b9cca4f7763e373", X"682e6ff3d6b2b8a3", 
                      X"748f82ee5defb2fc", X"78a5636f43172f60", X"84c87814a1f0ab72", X"8cc702081a6439ec", 
                      X"90befffa23631e28", X"a4506cebde82bde9", X"bef9a3f7b2c67915", X"c67178f2e372532b", 
                      X"ca273eceea26619c", X"d186b8c721c0c207", X"eada7dd6cde0eb1e", X"f57d4f7fee6ed178", 
                      X"06f067aa72176fba", X"0a637dc5a2c898a6", X"113f9804bef90dae", X"1b710b35131c471b", 
                      X"28db77f523047d84", X"32caab7b40c72493", X"3c9ebe0a15c9bebc", X"431d67c49c100d4c", 
                      X"4cc5d4becb3e42b6", X"597f299cfc657e2a", X"5fcb6fab3ad6faec", X"6c44198c4a475817");

   type W_d is array(0 to 63) of std_logic_vector(31 downto 0);
   signal W : W_d;
   
   signal mode_r   :  std_logic_vector(1 downto 0);
   signal data_counter            : unsigned(31 downto 0);
   signal a, b, c, d, e, f ,g ,h  : std_logic_vector(31 downto 0);
   signal available               : std_logic;
   signal block_valid, block_valid_r             : std_logic;
   signal new_word                : std_logic;
   signal WordsCount              : unsigned(4 downto 0);
   signal WordsC                  : integer range 0 to 128;
-- signal T1, T2, S0, S1, ch, temp1, temp2, maj : std_logic_vector(31 downto 0);
begin
available <= block_valid or new_word;
WordsC <= sha256_words when mode = "00" else
          sha512_words when mode = "11" else
          sha256_words;
process(rst, clk) 
variable S0, S1: std_logic_vector(31 downto 0);
begin

  if(rst = '0') then 
    W(0)   <= (others => '0');
    mode_r <= (others=>'0');
    block_valid <= '0';
  elsif(rising_edge(clk)) then
   -- if(init='1') then
      W(0) <= X"61626380"; -- abc
      for i in 1 to 13 loop
          W(i) <= (others => '0');
      end loop;
      W(14) <= X"00000000";
      W(15) <= X"00000018"; -- Size
   -- else
      -- for i in 0 to 15 loop
        -- S0 := rrot(W(16+i-15), 7) xor rrot(W(16+i-15), 18) xor rshft(W(16+i-15), 3);
        -- S1 := rrot(W(i-2), 17) xor rrot(W(i-2), 19) xor rshft(W(i-2), 10);
        -- W(i) <= std_logic_vector(unsigned(W(i-16)) + unsigned(S0) + unsigned(W(i-7)) + unsigned(S1));
      -- end loop;
   -- end if;
    WordsCount <= to_unsigned(sha256_words, WordsCount'length);
    for i in 16 to 63 loop
        -- s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)
          -- s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)
          -- w[i] := w[i-16] + s0 + w[i-7] + s1
          S0 := rrot(W(i-15), 7) xor rrot(W(i-15), 18) xor rshft(W(i-15), 3);
          S1 := rrot(W(i-2), 17) xor rrot(W(i-2), 19) xor rshft(W(i-2), 10);
          W(i) <= std_logic_vector(unsigned(W(i-16)) + unsigned(S0) + unsigned(W(i-7)) + unsigned(S1));
    end loop;
    
    if (setup = '1') then
      mode_r <= mode;
    end if;
    if(WordsCount = WordsC) then
      block_valid <= '1';
    end if;
  end if;
end process;



    -- S1 <= Sigma1(e);
    -- ch <= ch_fun(e, f, g); --(e and f) xor ((not e) and g)
    -- temp1 <= std_logic_vector(unsigned(h) + unsigned(S1) + unsigned(ch) + unsigned(K(to_integer(data_counter))) + unsigned(W(to_integer(data_counter))) );
    -- S0  <= Sigma0(a);
    -- maj <= (a and b) xor (a and c) xor (b and c);
    -- temp2 <= std_logic_vector(unsigned(S0) + unsigned(maj));

process(rst, clk)
variable T1, T2, S0, S1, ch, temp1, temp2, maj : std_logic_vector(31 downto 0);
 begin
if(rst = '0') then
  for i in 0 to 7 loop
    Hnew(i) <= HC(i);
  end loop;
  a <= HC(0); 
  b <= HC(1); 
  c <= HC(2); 
  d <= HC(3); 
  e <= HC(4); 
  f <= HC(5); 
  g <= HC(6); 
  h <= HC(7);
  data_counter <= (others => '0');
  block_valid_r <= '0';
elsif(rising_edge(clk)) then
  block_valid_r <= block_valid;
  if init = '1' then
    for i in 0 to 7 loop
      Hnew(i) <= HC(i);
    end loop;
    a <= HC(0); 
    b <= HC(1); 
    c <= HC(2); 
    d <= HC(3); 
    e <= HC(4); 
    f <= HC(5); 
    g <= HC(6); 
    h <= HC(7);
    data_counter <= (others => '0');
    S1 := (others => '0');
    S0 := (others => '0');
    ch := (others => '0');
    
  else
    if(available='1') then
      S1 := Sigma1(e);
      ch := ch_fun(e, f, g); --(e and f) xor ((not e) and g)
      temp1 := std_logic_vector(unsigned(h) + unsigned(S1) + unsigned(ch) + unsigned(K(to_integer(data_counter))(63 downto 32)) + unsigned(W(to_integer(data_counter(3 downto 0)))) );
      S0 := Sigma0(a);
      maj := (a and b) xor (a and c) xor (b and c);
      temp2 := addu(S0, maj);
      if data_counter = (sha256_rounds-1) then
        data_counter <= (others=>'0');
      else
        data_counter <= data_counter + 1;
      end if;
      h <= g;
      g <= f;
      f <= e;
      e <= addu(d, temp1);
      d <= c;
      c <= b;
      b <= a;
      a <= addu(temp1,temp2);
    end if;
    if(data_counter = 0 and block_valid_r = '1') then
      Hnew(0) <= addu(Hnew(0), a);--std_logic_vector(unsigned(HC(0)) + unsigned(a));
      Hnew(1) <= addu(Hnew(1), b);
      Hnew(2) <= addu(Hnew(2), c);
      Hnew(3) <= addu(Hnew(3), d);
      Hnew(4) <= addu(Hnew(4), e);
      Hnew(5) <= addu(Hnew(5), f);
      Hnew(6) <= addu(Hnew(6), g);
      Hnew(7) <= addu(Hnew(7), h);
    end if;
  end if;
end if;
end process;

output_V <= Hnew(0) & Hnew(1) & Hnew(2) & Hnew(3) & Hnew(4) & Hnew(5) & Hnew(6) & Hnew(7);

end architecture;
